package snowflake

import (
	"errors"
	"fmt"
	"log"
	"sync"
	"time"
)

const (
	epoch int64 = 1672531200000

	// 每部分占用的位数
	workerIDBits     int64 = 5  // 工作机器ID占用的位数
	datacenterIDBits int64 = 5  // 数据中心ID占用的位数
	sequenceBits     int64 = 12 // 序列号占用的位数

	// 每部分最大值
	maxWorkerID     int64 = -1 ^ (-1 << workerIDBits)     // 工作机器ID最大值 (31)
	maxDatacenterID int64 = -1 ^ (-1 << datacenterIDBits) // 数据中心ID最大值 (31)
	maxSequence     int64 = -1 ^ (-1 << sequenceBits)     // 序列号最大值 (4095)

	// 每部分向左的位移
	workerIDShift      int64 = sequenceBits                                   // 工作机器ID向左移动的位数 (12)
	datacenterIDShift  int64 = sequenceBits + workerIDBits                    // 数据中心ID向左移动的位数 (17)
	timestampLeftShift int64 = sequenceBits + workerIDBits + datacenterIDBits // 时间戳向左移动的位数 (22)
)

var SF *Snowflake

func init() {
	sf, err := NewSnowflake(1, 1)
	if err != nil {
		log.Fatalf("创建雪花算法实例失败: %v", err)
	}
	SF = sf
}

// Snowflake 结构体
type Snowflake struct {
	mu            sync.Mutex // 互斥锁
	lastTimestamp int64      // 上次生成ID的时间戳
	workerID      int64      // 工作机器ID
	datacenterID  int64      // 数据中心ID
	sequence      int64      // 序列号
}

// NewSnowflake 创建一个新的雪花算法实例
func NewSnowflake(datacenterID, workerID int64) (*Snowflake, error) {
	if datacenterID < 0 || datacenterID > maxDatacenterID {
		return nil, errors.New("datacenter ID must be between 0 and 31")
	}
	if workerID < 0 || workerID > maxWorkerID {
		return nil, errors.New("worker ID must be between 0 and 31")
	}
	return &Snowflake{
		lastTimestamp: -1,
		datacenterID:  datacenterID,
		workerID:      workerID,
		sequence:      0,
	}, nil
}

// NextID 生成下一个ID (返回19位的ID)
func (s *Snowflake) NextID() (int64, error) {
	s.mu.Lock()
	defer s.mu.Unlock()

	timestamp := time.Now().UnixMilli()

	// 如果当前时间小于上一次ID生成的时间戳，说明系统时钟回退过
	if timestamp < s.lastTimestamp {
		return 0, errors.New("clock moved backwards, refusing to generate ID")
	}

	// 如果是同一时间生成的，则进行序列号递增
	if timestamp == s.lastTimestamp {
		s.sequence = (s.sequence + 1) & maxSequence
		// 如果序列号溢出，则等待下一毫秒
		if s.sequence == 0 {
			for timestamp <= s.lastTimestamp {
				timestamp = time.Now().UnixMilli()
			}
		}
	} else {
		// 如果是新的时间戳，则重置序列号
		s.sequence = 0
	}

	s.lastTimestamp = timestamp

	// 生成ID
	id := ((timestamp - epoch) << timestampLeftShift) |
		(s.datacenterID << datacenterIDShift) |
		(s.workerID << workerIDShift) |
		s.sequence

	// 确保ID是19位
	// 检查ID的位数
	temp := id
	digits := 0
	for temp > 0 {
		temp /= 10
		digits++
	}

	// 如果ID不足19位，则通过添加尾部的0使其达到19位
	if digits < 19 {
		id *= power10(19 - digits)
	} else if digits > 19 {
		// 如果ID超过19位，则截断
		id /= power10(digits - 19)
	}

	return id, nil
}

// power10 计算10的n次方
func power10(n int) int64 {
	result := int64(1)
	for i := 0; i < n; i++ {
		result *= 10
	}
	return result
}

// Format 将ID格式化为固定19位的字符串
func Format(id int64) string {
	return fmt.Sprintf("%019d", id)
}
